﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using BrainTechLLC.ThreadSafeObjects;
using System.Runtime.Serialization;
using System.Reflection;

namespace BrainTechLLC
{
    public static class ActionAndOrderRegistry
    {
        public static ThreadSafeLookup<string, ActionAndOrder> Lookup = new ThreadSafeLookup<string, ActionAndOrder>();

        public static bool Register(this ActionAndOrder item)
        {
            return Lookup.AddIfNew(item.FriendlyName, () => item);
        }
    }

    public class ActionAndOrderCollection : List<ActionAndOrder>
    {
        public int OrderActions()
        {
            Sort(new Comparison<ActionAndOrder>((a, b) =>
            {
                int comp1 = a.RequestedOrder.CompareTo(b.RequestedOrder);

                if (comp1 != 0)
                    return comp1;

                int comp2 = a.Priority.CompareTo(b.Priority);

                return comp2;
            }));

            int totalTries = 0;

        TryAgain:
            if (totalTries++ == 10000)
                throw new Exception("Circular Dependencies exist");

            for (int n = 0; n < Count; n++)
            {
                ActionAndOrder examining = this[n];
                if (examining.Dependencies != null)
                {
                    bool correctlyOrdered = true;

                    for (int a = 0; a < examining.Dependencies.Count; a++)
                    {
                        ActionAndOrder dependency = examining.Dependencies[a];

                        for (int b = n + 1; b < Count; b++)
                        {
                            ActionAndOrder other = this[b];
                            if (other.FriendlyName == dependency.FriendlyName)
                            {
                                this.MoveDown(item => item.FriendlyName.Equals(examining.FriendlyName));
                                correctlyOrdered = false;
                            }

                            if (!correctlyOrdered)
                                goto TryAgain;
                        }
                    }
                }
            }

            return totalTries;
        }
    }

    [DataContract]
    [Serializable]
    public class ActionAndOrder
    {
        [NonSerialized]
        public object _lock;

        [DataMember]
        protected DynamicMethod _action;

        [DataMember]
        protected int _priority;

        [DataMember]
        protected int _requestOrder;

        [DataMember]
        protected string _friendlyName;

        [DataMember]
        protected List<string> _nameDependencies;

        public List<string> NameDependencies { get { return _nameDependencies; } set { _nameDependencies = value; } }
        public DynamicMethod Action { get { return _action; } set { _action = value; } }
        public int Priority { get { return _priority; } set { _priority = value; } }
        public int RequestedOrder { get { return _requestOrder; } set { _requestOrder = value; } }
        public string FriendlyName { get { return _friendlyName; } set { _friendlyName = value; } }

        [NonSerialized]
        protected List<ActionAndOrder> _dependencies;

        public List<ActionAndOrder> Dependencies
        {
            get
            {
                if (_lock == null)
                    Interlocked.CompareExchange<object>(ref _lock, new object(), null);

                if (_dependencies == null)
                {
                    lock (_lock)
                    {
                        if (_dependencies == null)
                        {
                            List<ActionAndOrder> temp = new List<ActionAndOrder>();
                            if (NameDependencies != null)
                            {
                                for (int n = 0; n < NameDependencies.Count; n++)
                                {
                                    ActionAndOrder item = ActionAndOrderRegistry.Lookup[NameDependencies[n]];
                                    if (item == null)
                                    {
                                        // throw exception?
                                    }
                                    else
                                    {
                                        temp.Add(item);
                                    }
                                }
                            }
                            Interlocked.CompareExchange<List<ActionAndOrder>>(ref _dependencies, temp, null);
                        }
                    }
                }

                return _dependencies;
            }
        }

        [MethodVisible]
        public static ActionAndOrder Create(DynamicMethod method, int requestOrder, string friendlyName)
        {
            ActionAndOrder result = new ActionAndOrder()
            {
                FriendlyName = friendlyName,
                RequestedOrder = requestOrder,
                Action = method
            };

            return result;
        }

        [MethodVisible]
        public static ActionAndOrder Create(DynamicMethod method, int requestOrder, int priority, string friendlyName)
        {
            ActionAndOrder result = Create(method, requestOrder, friendlyName);
            result.Priority = priority;
            return result;
        }

        [MethodVisible]
        public static ActionAndOrder Create(DynamicMethod method, int requestOrder, int priority, string friendlyName, params string[] dependencies)
        {
            ActionAndOrder result = Create(method, requestOrder, friendlyName);
            result.Priority = priority;
            result.NameDependencies = new List<string>(dependencies);
            return result;
        }
    }

    public static class ActionExtMethods
    {

    }
}